#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

"""
This file is part of playlistbs.

@author: Romain RICHARD
@contact: romain.richard.IT.engineer@gmail.com
@version: 2.0
@copyright: GPLv3

@todo: Find the best subtitle in a zip file

@change: 2012-09-17: Used pylint to clean up the code
@change: 2011-11-19: Handle VOVF subtitles
@change: 2011-11-08: Subtitles are downloaded and renamed
@change: 2011-08-20: Creation of the file
"""

import mimetypes

from os import remove, rename
from os.path import dirname, exists, splitext
from re import match
from urllib import urlretrieve
from zipfile import BadZipfile, ZipFile

from playlist_betaseries.episode import Episode


FILENAME = r"""
    (?P<episode>.*?)(\.(?P<hd>720p))?\.(?P<quality>\\d{1})\.
    (?P<language>V[FO])(\.\\d+)?\.srt$
"""
LANGUAGES = ["VO", "VF"]


class Subtitle(object):
    """A subtitle."""

    def __init__(self, episode=Episode(), language="", file_="", url="",
                 quality=5, hd=False, local_file=""):
        self.episode = episode
        self.language = language
        self.file = file_
        self.url = url
        self.quality = quality
        self.hd = hd
        self.local_file = local_file

    def __str__(self):
        return ("{ep} {hd} {quality} {language}"
                .format(ep=self.episode, hd=("720p" if self.hd else ""),
                        quality=self.quality, language=self.language))

    def __gt__(self, other):
        self_language_rank = (self.episode.show.__getattribute__("{v}_subs".format(v=self.language.lower()))
                              if hasattr(self.episode.show, "{v}_subs".format(v=self.language.lower()))
                              else min([self.episode.show.__getattribute__("{v}_subs".format(v=language.lower())) for language in LANGUAGES]))
        other_language_rank = (other.episode.show.__getattribute__("{v}_subs".format(v=other.language.lower()))
                               if hasattr(other.episode.show, "{v}_subs".format(v=other.language.lower()))
                               else min([other.episode.show.__getattribute__("{v}_subs".format(v=language.lower())) for language in LANGUAGES]))
        return (self_language_rank < other_language_rank or
                self_language_rank == other_language_rank and self.episode.hd == self.hd and self.episode.hd != other.hd or
                self_language_rank == other_language_rank and self.hd == other.hd and self.quality < other.quality)

    def __non_zero__(self):
        return any(self.episode, self.language, self.file, self.url, self.hd,
                   self.local_file)

    @classmethod
    def from_file(cls, episode, file_):
        """Create a subtitle from a file_.

        @type episode: Episode
        @param episode: The episode

        @type file_: String
        @param file_: The path of the file_

        @rtype: Subtitle
        @return: The subtitle created from the Node

        """
        kwargs = {}

        r = match(FILENAME, file_)
        if r and r.group("episode") == splitext(episode.file)[0]:
            kwargs["episode"] = episode
            kwargs["language"] = r.group("language")
            kwargs["quality"] = int(r.group("quality"))
            kwargs["hd"] = bool(r.group("hd"))
            kwargs["local_file"] = file_

        return cls(**kwargs)

    @classmethod
    def from_node(cls, episode, node):
        """Create a subtitle from a Node.

        @type episode: Episode
        @param episode: The episode

        @type node: Node
        @param node: The node containing the subtitle's information

        @rtype: Subtitle
        @return: The subtitle created from the Node

        """
        kwargs = {}

        kwargs["episode"] = episode
        kwargs["language"] = node.getElementsByTagName("language")[0].firstChild.data.strip()
        kwargs["file"] = node.getElementsByTagName("file")[0].firstChild.data.strip()
        kwargs["url"] = node.getElementsByTagName("url")[0].firstChild.data.strip()
        kwargs["quality"] = 6 - int(node.getElementsByTagName("quality")[0].firstChild.data.strip())
        kwargs["hd"] = node.getElementsByTagName("file")[0].firstChild.data.strip().lower().find("720p") >= 0

        return cls(**kwargs)

    def download(self):
        """Download the subtitle and save it in the older."""
        local_file = "{path}/{file}".format(path=dirname(self.episode.file),
                                            file=self.file)
        urlretrieve(self.url, local_file)

        mimetypes.init()
        if mimetypes.guess_type(local_file)[0] == "application/zip":
            try:
                zip_file = ZipFile(local_file)
            except BadZipfile:
                remove(local_file)
                return
            best_sub = self.find_best_sub_in_zip_file(zip_file)
            # TODO: Change if necessary self.hd depending on the sub
            zip_file.extract(best_sub, path=dirname(self.episode.file))
            remove(local_file)
            local_file = "{path}/{file}".format(path=dirname(self.episode.file),
                                                file=best_sub)

        rename(local_file, "{ep}{hd}.{quality}.{language}.srt"
                           .format(ep=splitext(self.episode.file)[0],
                                   hd=(".720p" if self.hd else ""),
                                   quality=self.quality,
                                   language=self.language))

    def delete(self):
        """Delete the subtitles from the computer."""
        if exists(self.local_file):
            remove(self.local_file)

    def is_better_than(self, subs):
        """Return the list of subtitles that this subtitle is better than.

        @type subs: List
        @param subs: List of subtitles

        @rtype: List
        @return: List of subtitles that this subtitle is better than

        """
        return [sub for sub in subs if self > sub]

    def find_best_sub_in_zip_file(self, zip_file):
        """Find the best subtitles in the zip file.

        @type zip_file: ZipFile
        @param zip_file: The zip file containing the subtitles

        @rtype: String
        @return: The name of the best subtitle in the zip file

        """
        return zip_file.namelist()[0]
